package com.wanger.swc.util.validation;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.func.Func0;
import cn.hutool.core.lang.func.LambdaUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.wanger.swc.exception.BusEx;
import com.wanger.swc.util.json.MyJson;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Map;

/**
 * @Author: wanger
 * @Date: 2024/9/30 0:52
 * @Description: 自定义校验工具
 */
@Slf4j
public class MyVerifyUtil {
    //2.时间区间验证

    /**
     * @param funStart 获取起始时间的方法
     * @param funEnd   获取结束时间的方法
     */
    public static void dateSequenceVerify(Func0<String> funStart, Func0<String> funEnd) {
        String dateStart = nullVerify(funStart);
        String dateEnd = nullVerify(funEnd);
        String startComment = getComment(funStart);
        String endComment = getComment(funEnd);
        dateSequenceVerify(dateStart, dateEnd, startComment + "必须在" + endComment + "之前");
    }


    /**
     * 时间顺序验证
     *
     * @param dateStart 起始时间
     * @param dataEnd   结束时间
     * @param msg       验证不通过的提示
     */
    public static void dateSequenceVerify(String dateStart, String dataEnd, String msg) {
        DateTime start = DateUtil.parse(dateStart);
        DateTime end = DateUtil.parse(dataEnd);
        if (start.isAfter(end)) BusEx.throwEx(msg);
    }

    /**
     * 时间格式验证
     *
     * @param fun    要验证格式的方法
     * @param format 指定格式
     */
    public static void dateFormatVerify(Func0<String> fun, String format) {
        dateFormatVerify(
                nullVerify(fun),
                format,
                StrUtil.format("{field} 时间格式验证失败，格式只能是【{format}】",
                        MyJson.map()
                                .pu("field", getComment(fun))
                                .pu("format", format))
        );
    }

    /**
     * 时间格式验证
     *
     * @param date   要验证的时间
     * @param format 指定格式
     * @param msg    验证不通过的提示
     * @param params 提示内容的多个参数！
     */
    public static void dateFormatVerify(String date, String format, String msg, Object... params) {
        dateFormatVerify(date, format, StrUtil.format(msg, params));
    }

    /**
     * 时间格式验证
     *
     * @param date   要验证的时间
     * @param format 指定格式
     * @param msg    验证不通过的提示
     */
    public static void dateFormatVerify(String date, String format, String msg) {
        try {
            DateUtil.parse(date, format);
        } catch (Exception e) {
            BusEx.throwEx(msg);
        }
    }

    /**
     * 空值或者空数据检查
     *
     * @param value 要检查的值
     * @param <T>   数据类型泛型
     * @return 是否为空或者blank
     */
    public static <T> boolean nullCheck(T value) {
        if (value instanceof String) {
            return StrUtil.isBlank((String) value);
        } else if (value instanceof Iterable<?>) {
            return CollUtil.isEmpty((Collection<?>) value);
        } else if (value instanceof Map<?, ?>) {
            return CollUtil.isEmpty((Map<?, ?>) value);
        } else if (value instanceof Enumeration<?>) {
            return CollUtil.isEmpty((Enumeration<?>) value);
        } else if (ArrayUtil.isArray(value)) {
            return ArrayUtil.isEmpty(value);
        } else {
            return value == null;
        }
    }

    /**
     * 请求参数验证
     *
     * @param value 要验证的值
     * @param <T>   数据类型泛型
     * @return 验证后的值
     */
    public static <T> T queryNullVerify(T value) {
        nullVerify(value, "请求参数不能为空！");
        return value;
    }

    /**
     * 空数据值验证
     *
     * @param value  要验证的值
     * @param msg    空数据异常提示
     * @param params msg 参数
     * @param <T>    数据类型泛型
     */
    public static <T> T nullVerify(T value, String msg, Object... params) {
        return nullVerify(value, StrUtil.format(msg, params));
    }

    /**
     * 空数据值验证
     *
     * @param value 要验证的值
     * @param msg   空数据异常提示
     * @param <T>   数据类型泛型
     */
    public static <T> T nullVerify(T value, String msg) {
        if (nullCheck(value)) BusEx.throwEx(msg);
        return value;
    }

    /**
     * 空数据验证
     *
     * @param funs 要验证数据的方法
     */
    public static void nullVerify(Func0<?>... funs) {
        nullVerify(funs, "要验证的字段列表不能为空！");
        for (Func0<?> fun : funs) nullVerify(fun);
    }

    /**
     * 空数据验证
     *
     * @param fun 要验证数据的方法
     * @param <T> 数据类型泛型
     */
    public static <T> T nullVerify(Func0<T> fun) {
        return nullVerify(fun, getComment(fun) + " 不能为空！");
    }

    /**
     * 获取字段注释
     *
     * @param fun 要获取注释的方法
     * @param <T> 数据类型泛型
     * @return 字段注释
     */
    private static <T> String getComment(Func0<T> fun) {
        try {
            Class<Object> realClass = LambdaUtil.getRealClass(fun);
            String comment = null;
            Field field = realClass.getDeclaredField(LambdaUtil.getFieldName(fun));
            ApiModelProperty apiModel = field.getAnnotation(ApiModelProperty.class);
            if (apiModel != null && StrUtil.isNotBlank(apiModel.value())) comment = apiModel.value();
            if (StrUtil.isNotBlank(comment)) {
                return "【" + field.getName() + ":" + comment + "】";
            } else {
                return "【" + field.getName() + "】";
            }
        } catch (BusEx e) {//正常业务异常就正常抛出
            throw e;
        } catch (Exception e) {//调用异常暂不处理
            throw BusEx.create("校验调用目标fun出错！");
        }
    }

    /**
     * 空数据验证
     *
     * @param fun    获取数据的方法
     * @param msg    异常提示信息
     * @param params msg 参数
     * @param <T>    数据类型
     * @return 数据
     */
    public static <T> T nullVerify(Func0<T> fun, String msg, Object... params) {
        return nullVerify(fun, StrUtil.format(msg, params));
    }

    /**
     * 空数据验证
     *
     * @param fun 获取数据的方法
     * @param msg 异常提示信息
     * @param <T> 数据类型
     * @return 数据
     */
    public static <T> T nullVerify(Func0<T> fun, String msg) {
        try {
            return nullVerify(fun.call(), msg);
        } catch (BusEx e) {//正常业务异常就正常抛出
            throw e;
        } catch (Exception e) {//调用异常暂不处理
            throw BusEx.create("校验调用目标fun出错！");
        }
    }
}
